package demo04;

/*
 *  Waiting状态：线程处于无限等待状态
 *  进入该状态，需要有两条线程，一条进入，一条负责唤醒
 *  两条线程内的代码需要在有同一把锁的同步代码块/同步方法内，它们的锁就是对象监视器，负责调用线程1的等待命令与线程2的唤醒命令
 */
public class Demo01Waiting {
    public static void main(String[] args) {
        Object object = new Object(); // 同步代码块的锁，也是对象监视器，调用等待和唤醒的命令

        new Thread(new Runnable() {
            @Override
            public void run() { // 线程1的任务：下单等包子/包子做好后吃包子
                synchronized (object) {
                    System.out.println("顾客扫码支付3￥，购买菜包*1...");
                    try { // wait方法抛出编译器异常InterruptedException中断异常，需要捕获处理
                        object.wait(); // 线程1进入等待状态
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("顾客收到包子，离开...");
                } // 线程1释放锁
            }
        }).start(); // 线程1
        
        new Thread(new Runnable() {
            @Override
            public void run() { // 线程2的任务：做包子
                try { // 线程2先进入计时等待0.01s，防止抢跑
                    Thread.sleep(10);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
                synchronized (object) {
                    System.out.println("老板收款，做包子用时5s...");
                    try { // wait方法抛出编译器异常InterruptedException中断异常，需要捕获处理
                        Thread.sleep(5000); // 线程2进入计时等待状态
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    object.notify(); // 线程2唤醒线程1
                    System.out.println("包子做好了，交给顾客...");
                } // 线程2释放锁
            }
        }).start(); // 线程2

        /*
         *  输出结果分析：
         *  顾客扫码支付3￥，购买菜包*1...
         *      顾客线程：运行
         *      老板线程：计时等待
         *  老板收款，做包子用时5s...
         *      顾客线程：无限等待（wait()）
         *      老板线程：运行
         *  包子做好了，交给顾客...
         *      顾客线程：锁阻塞
         *      老板线程：运行（notify()）
         *  顾客收到包子，离开...
         *      顾客线程：运行
         *      老板线程：终止
         */
    }
}
